//小程序蓝牙API封装

//初始化蓝牙模块 mode:central主机模式/peripheral从机模式
const bleOpenAdapter = (mode)=>{
 console.log("bleOpenAdapter 模式是: "+mode)
  return  wx.openBluetoothAdapter(
    {
      mode:mode||central
    }
  ) 
}
//关闭蓝牙模块 调用该方法将断开所有已建立的连接并释放系统资源。
//在使用蓝牙流程后，与 wx.openBluetoothAdapter 成对调用
const bleCloseAdapter = ()=>{
  console.log("bleOpenAdapter")
   return  wx.closeBluetoothAdapter()
   
 }
//开始搜寻附近的蓝牙外围设备
//蓝牙设备会广播自己的主 service 的 UUID置此参数，则只搜索广播包有对应 UUID 的主服务的蓝牙设备。可通过该参数过滤掉周边不需要处理的其他蓝牙设备
//是否允许重复上报同一设备。如果允许重复上报，则 wx.onBlueToothDeviceFound 方法会多次上报同一设备，但是RSSI值会有不同
//开发调试时请使用true  小程序重启并不会自动清空已发现设备 导致wx.onBluetoothDeviceFound始终无法调用
const bleStartSearch = (services,allowDuplicatesKey)=>{
  console.log("bleStartSearch")
  console.log(services)
   return  wx.startBluetoothDevicesDiscovery(
     {
      services:services,
      allowDuplicatesKey:allowDuplicatesKey
     }
   ) 
 }
//停止搜寻附近的蓝牙外围设备。若已经找到需要的蓝牙设备并不需要继续搜索时，建议调用该接口停止蓝牙搜索
const bleStopSearch = ()=>{
  console.log("bleStopSearch")
   return  wx.stopBluetoothDevicesDiscovery() 
 }
//监听搜索到新设备的事件 !本方法不支持以Promise风格调用
const bleOnDeviceFound = (func)=>{
  console.log("bleOnDeviceFound")
  wx.onBluetoothDeviceFound(function(res) {
    var devices = res.devices;
    console.log('new device list has founded')
    console.dir(devices)
    console.log(ab2hex(devices[0].advertisData))
    //回调
    func(devices)
  })
}
//停止监听搜索到新设备的事件 !本方法不支持以Promise风格调用
const bleoffDeviceFound = ()=>{
  console.log("bleoffDeviceFoundBtn")
   return  wx.offBluetoothDeviceFound() 
 }

//连接蓝牙低功耗外设
//若小程序在之前已有搜索过某个蓝牙设备，并成功建立连接，可直接传入之前搜索获取的 deviceId 直接尝试连接该设备，无需再次进行搜索操作
const bleCreateConnect = (deviceId)=>{
  console.log("bleCreateConnectBtn")
   return  wx.createBLEConnection(
     {
         deviceId:deviceId
     }
   ) 
 }
//断开蓝牙低功耗外设
const bleCloseConnect = (deviceId)=>{
  console.log("bleCloseConnect")
   return  wx.closeBLEConnection(
     {
         deviceId:deviceId
     }
   ) 
 }
/*注意
请保证尽量成对的调用 wx.createBLEConnection 和 wx.closeBLEConnection 接口。安卓如果重复调用 wx.createBLEConnection 创建连接，有可能导致系统持有同一设备多个连接的实例，导致调用 closeBLEConnection 的时候并不能真正的断开与设备的连接。
蓝牙连接随时可能断开，建议监听 wx.onBLEConnectionStateChange 回调事件，当蓝牙设备断开时按需执行重连操作
若对未连接的设备或已断开连接的设备调用数据读写操作的接口，会返回 10006 错误，建议进行重连操作
*/

//获取蓝牙低功耗设备所有服务 (service) 需要已经通过 wx.createBLEConnection 建立连接
const  bleGetServices= (deviceId)=>{
  console.log("bleGetServices")
   return  wx.getBLEDeviceServices({
     deviceId:deviceId
   }) 
 }
 //获取蓝牙低功耗设备某个服务中所有特征 (characteristic)
//即使事先已经知道某个serviceId蓝牙服务 UUID。 但让然需要调用wx.getBLEDeviceServices之后才能使用该serviceId
const  bleGetCharacteristic= (deviceId,serviceId)=>{
  console.log("bleGetCharacteristic")
   return  wx.getBLEDeviceCharacteristics({
    deviceId:deviceId,
    serviceId:serviceId
   }) 
 }
//读取蓝牙低功耗设备特征值的二进制数据。
//注意：必须设备的特征支持read才可以成功调用.是否支持请查询硬件说明书
const  bleReadCharacteristicValue= (deviceId,serviceId,characteristicId)=>{
  console.log("bleReadCharacteristicValue")
   return  wx.readBLECharacteristicValue({
    deviceId:deviceId,
    serviceId:serviceId,
    characteristicId:characteristicId
   }) 
 }
//向蓝牙低功耗设备特征值中写入二进制数据。
//注意：必须设备的特征支持write才可以成功调用.是否支持请查询硬件说明书
//value为ArrayBuffer类型
const  bleWriteCharacteristicValue= (deviceId,serviceId,characteristicId,value)=>{
  console.log("bleWriteCharacteristicValue")
   return  wx.writeBLECharacteristicValue({
    deviceId:deviceId,
    serviceId:serviceId,
    characteristicId:characteristicId,
    value:stringToBytes(value),
   }) 
 }
//启用蓝牙低功耗设备特征值变化时的 notify 功能，订阅特征。注意：必须设备的特征支持 notify 或者 indicate 才可以成功调用
const  bleNotifyCharacteristicValueChange= (deviceId,serviceId,characteristicId)=>{
  console.log("bleNotifyCharacteristicValueChange")
   return  wx.notifyBLECharacteristicValueChange({
    deviceId:deviceId,
    serviceId:serviceId,
    characteristicId:characteristicId,
    state:true
   }) 
 }
//监听蓝牙低功耗设备的特征值变化事件
//必须先启用 wx.notifyBLECharacteristicValueChange
const  bleOnCharacteristicValueChange= (func)=>{
  console.log("bleOnCharacteristicValueChange")
   return  wx.onBLECharacteristicValueChange(function(res) {
    console.log(`characteristic ${res.characteristicId} has changed, now is ${res.value}`)
    console.log(ab2hex(res.value))
    func(res)
  }) 
 }

module.exports = {
  bleOpenAdapter,
  bleCloseAdapter,
  bleStartSearch,
  bleStopSearch,
  bleOnDeviceFound,
  bleoffDeviceFound,
  bleCreateConnect,
  bleCloseConnect,
  bleGetServices,
  bleGetCharacteristic,
  bleReadCharacteristicValue,
  bleWriteCharacteristicValue,
  bleNotifyCharacteristicValueChange,
  bleOnCharacteristicValueChange
}

function ab2hex(buffer) {
  var hexArr = Array.prototype.map.call(
    new Uint8Array(buffer),
    function(bit) {
      return ('00' + bit.toString(16)).slice(-2)
    }
  )
  return hexArr.join('');
}
// 字符串转byte
function stringToBytes(str) {
  var array = new Uint8Array(str.length);
  for (var i = 0, l = str.length; i < l; i++) {
    array[i] = str.charCodeAt(i);
  }
  console.log(array);
  return array.buffer;
}